package com.sinodata.bsm.cicp.collector.common;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;

import com.sinodata.bsm.cicp.collector.Collector;
import com.sinodata.bsm.cicp.exception.CollectorException;
import com.sinodata.bsm.cicp.util.CommandReader;
import com.sinodata.bsm.common.vo.ResPropertyValue;
import com.sinodata.bsm.common.vo.ResPropertyValue.PropValue;

/**
 * 
 * <p>
 * Description: 
 * </p>
 *
 * @author wangpeng
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-8-13 下午04:17:16          wangpeng        1.0         To create
 * </p>
 *
 * @since 
 * @see
 */
public class AppServicePing extends Collector {

    private static final Logger logger = Logger.getLogger(AppServicePing.class);

    //private static final String cmd = "uname";
    //private static final String OS_Windows = "Windows";
    private static final String OS_Linux = "Linux";
    private static final String OS_AIX = "AIX";
    private static final String OS_Solaris = "SunOS";
    private static final String OS_HP = "HP-UX";
    private static final String OS_Tru64 = "OSF1";

    // 各个平台下执行命令的模板
    private static final String cmd_Windows = "ping ";
    private static final String cmd_Linux = "ping -c 5 ";
    private static final String cmd_AIX = "ping -c 10 ";
    private static final String cmd_Solaris = "ping -s ";
    private static final String cmd_HP = "ping ";
    private static final String cmd_Tru64 = "/usr/sbin/ping -c 5 ";

    //private static final String rut_windows = "\\s+Packets:\\s+Sent\\s+=\\s+(\\d+),\\s+Received\\s+=\\s+(\\d+),\\s+Lost\\s+=\\s+\\d+\\s+\\((\\d+)%.*";
    private static final String rut_windows = "\\s+\\S+\\s+\\S+\\s+=\\s+(\\d+)(?:,\\s+)?\\S+\\s+=\\s+(\\d+)(?:,\\s+)?\\S+\\s+=\\s+\\d+\\s+\\((\\d+)%.*";
    //private static final String rut_windowsA = "\\s+Minimum\\s+=\\s+(\\d+\\.*\\d*)ms,\\s+Maximum\\s+=\\s+(\\d+\\.*\\d*)ms,\\s+Average\\s+=\\s+(\\d+\\.*\\d*)ms.*";
    private static final String rut_windowsA = "\\s+\\S+\\s+=\\s+(\\d+\\.*\\d*)ms(?:,\\s+)?\\S+\\s+=\\s+(\\d+\\.*\\d*)ms(?:,\\s+)?\\S+\\s+=\\s+(\\d+\\.*\\d*)ms.*";
    private static final String rut_linux = "(\\d+)\\s+packets\\s+transmitted,\\s+(\\d+)\\s+received.*,\\s+(\\d+)%.*";
    private static final String rut_linuxA = "rtt\\s+min/avg/max/mdev\\s+=\\s+(\\d+\\.*\\d*)/(\\d+\\.*\\d*)/(\\d+\\.*\\d*).*";
    private static final String rut_aix = "(\\d+)\\s+packets\\s+transmitted,\\s+(\\d+)\\s+packets\\s+received,\\s+(\\d+)%.*";
    private static final String rut_aixA = "round\\-trip\\s+min/avg/max\\s+=\\s+(\\d+\\.*\\d*)/(\\d+\\.*\\d*)/(\\d+\\.*\\d*).*";
    private static final String rut_solaris = "(\\d+)\\s+packets\\s+transmitted,\\s+(\\d+)\\s+packets\\s+received,\\s+(\\d+)%.*";
    private static final String rut_solarisA = "\\s*round-trip\\s+\\(ms\\)\\s+min/avg/max/stddev\\s+=\\s+(\\d+\\.*\\d*)/(\\d+\\.*\\d*)/(\\d+\\.*\\d*).*";
    private static final String rut_hp = "(\\d+)\\s+packets\\s+transmitted,\\s+(\\d+)\\s+packets\\s+received,\\s+(\\d+)%.*";
    private static final String rut_hpA = "round\\-trip\\s+\\(ms\\)\\s+min/avg/max\\s+=\\s+(\\d+\\.*\\d*)/(\\d+\\.*\\d*)/(\\d+\\.*\\d*).*";

    public AppServicePing() {
    }

    @Override
    public List<ResPropertyValue> collect(String ip) throws CollectorException {
        String pIp = this.getParamMap().get("Origin_Ip");//ping命令发起端
        String pOs = this.getParamMap().get("Origin_Os");
        String cIp = this.getParamMap().get("Destination IP of Ping Command");//ping命令接收端
        List<ResPropertyValue> value = testPing(pIp, pOs, cIp);
        if (value != null) {
            PropValue[] result = value.get(0).getValues();
            //丢包率大于80%或者平均时间大于1000ms就重新测试
            if (Double.valueOf(result[2].value) != 0 || Double.valueOf(result[5].value) > 1000) {
                try {
                    Thread.sleep(10000);
                } catch (Exception ex) {
                    logger.error("failed to ping host", ex);
                    throw new CollectorException(ex);
                }
                value = testPing(pIp, pOs, cIp);
            }
        }
        return value;
    }

    /**
     * 执行ping命令的过程
     * @param pIp
     * @param cIp
     * @return
     * @throws CollectorException 
     */
    @SuppressWarnings({ "rawtypes" })
    private List<ResPropertyValue> testPing(String pIps, String pOs, String cIp) throws CollectorException {
        List<ResPropertyValue> values = new ArrayList<ResPropertyValue>();
        String[] propMetas = getPropMeta();
        ResPropertyValue propertyValueX = new ResPropertyValue();
        ResPropertyValue.PropValue[] propValues = new ResPropertyValue.PropValue[propMetas.length];
        for (int i = 0; i < propValues.length; i++) {
            propValues[i] = ResPropertyValue.createPropValue("0", propMetas[i]);
        }
        String pingCmd = null;
        BufferedReader br = null;
        try {
            List l = new ArrayList();
            if (pIps != null && !pIps.equals("") && pOs != null && !pOs.equals("")) {
                pingCmd = getCommand(pOs, cIp);
                br = CommandReader.getReader(pIps, pingCmd, 10 * 60 * 1000, 10 * 60 * 1000);
                l = getPatternBypOs(pOs);
            } else {
                pingCmd = getCommand(cIp);
                br = CommandReader.getLocalReader(pingCmd, 0, 0);
                l = getPattern(System.getProperty("sun.desktop"));
            }
            String line = null;
            if (l == null || l.size() < 3) {
                return null;
            }
            if ((l.get(0) instanceof Pattern) && (l.get(1) instanceof Pattern)) {
                Pattern CURRENT_PATTERN1 = (Pattern) l.get(0);
                Pattern CURRENT_PATTERN2 = (Pattern) l.get(1);
                while ((line = br.readLine()) != null) {
                    // result中的发包，收包，以及收包率
                    Matcher match = CURRENT_PATTERN1.matcher(line);
                    if (match.find()) {
                        propValues[0] = ResPropertyValue.createPropValue(match.group(1).trim(), propMetas[0]);
                        propValues[1] = ResPropertyValue.createPropValue(match.group(2).trim(), propMetas[1]);
                        propValues[2] = ResPropertyValue.createPropValue(match.group(3).trim(), propMetas[2]);
                    }
                    /*
                     * 根据操作系统的类型不同，对它们显示方式不同作相 应处理，使得result中都是按照最小最大平均排列
                     */
                    if (l.get(2) instanceof String) {
                        String TYPE = (String) l.get(2);
                        if (TYPE.equalsIgnoreCase("windows")) {
                            Matcher matcher = CURRENT_PATTERN2.matcher(line);
                            if (matcher.find()) {
                                propValues[3] = ResPropertyValue.createPropValue(matcher.group(1).trim(), propMetas[3]);
                                propValues[4] = ResPropertyValue.createPropValue(matcher.group(2).trim(), propMetas[4]);
                                propValues[5] = ResPropertyValue.createPropValue(matcher.group(3).trim(), propMetas[5]);
                                break;
                            }
                        }
                        if ((TYPE.equalsIgnoreCase("linux")) || (TYPE.equals("aix")) || (TYPE.equals("hp")) || (TYPE.equals("solaris"))) {
                            Matcher matcher = CURRENT_PATTERN2.matcher(line);
                            if (matcher.find()) {
                                propValues[3] = ResPropertyValue.createPropValue(matcher.group(1).trim(), propMetas[3]);
                                propValues[4] = ResPropertyValue.createPropValue(matcher.group(2).trim(), propMetas[4]);
                                propValues[5] = ResPropertyValue.createPropValue(matcher.group(3).trim(), propMetas[5]);
                                break;
                            }
                        }
                    }
                }
            }
            propValues[6] = ResPropertyValue.createPropValue(propValues[4].value, propMetas[6]);
            if (propValues[2].value.matches("\\d+") && !(Integer.valueOf(propValues[2].value) >= 100)) {
                propValues[7] = ResPropertyValue.createPropValue("1", propMetas[7]);
            } else {
                propValues[7] = ResPropertyValue.createPropValue("0", propMetas[7]);
            }
            propertyValueX.setValues(propValues);
            values.add(propertyValueX);
        } catch (IOException ex) {
            logger.error("failed to test ping", ex);
            values.add(propertyValueX);
            //return values;
        } finally {
            try {
                br.close();
            } catch (IOException e) {
                logger.error("failed to close BufferedReader", e);
            }
        }
        return values;
    }

    /**
     * getPattern
     *
     * @return Pattern集合及操作系统类型
     * @throws CollectorException 
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    private List getPattern(String osName) throws CollectorException {
        List l = new ArrayList();
        if (osName.equalsIgnoreCase("windows")) {
            l.add(Pattern.compile(rut_windows));
            l.add(Pattern.compile(rut_windowsA));
            l.add("windows");
            return l;
        }
        // 返回适合该cmdserver所在操作系统的ping命令
        if (osName.equalsIgnoreCase(OS_Linux)) {
            l.add(Pattern.compile(rut_linux));
            l.add(Pattern.compile(rut_linuxA));
            l.add("linux");
            return l;
            // return compiler.compile(rut_linux);
        } else if (osName.equalsIgnoreCase(OS_AIX)) {
            l.add(Pattern.compile(rut_aix));
            l.add(Pattern.compile(rut_aixA));
            l.add("aix");
            return l;
            // return compiler.compile(rut_aix);
        } else if (osName.equalsIgnoreCase(OS_Solaris)) {
            l.add(Pattern.compile(rut_solaris));
            l.add(Pattern.compile(rut_solarisA));
            l.add("solaris");
            return l;
            // return compiler.compile(rut_solaris);
        } else if (osName.equalsIgnoreCase(OS_HP)) {
            l.add(Pattern.compile(rut_hp));
            l.add(Pattern.compile(rut_hpA));
            l.add("hp");
            return l;
        } else if (osName.equalsIgnoreCase(OS_Tru64)) {
            // return compiler.compile(rut_Tru64);
        }
        return null;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private List getPatternBypOs(String pOs) throws CollectorException {
        List l = new ArrayList();
        if ("windows".contains(pOs.toLowerCase())) {
            l.add(Pattern.compile(rut_windows));
            l.add(Pattern.compile(rut_windowsA));
            l.add("windows");
            return l;
        }
        // 返回适合该cmdserver所在操作系统的ping命令
        if ("linux".contains(pOs.toLowerCase())) {
            l.add(Pattern.compile(rut_linux));
            l.add(Pattern.compile(rut_linuxA));
            l.add("linux");
            return l;
            // return compiler.compile(rut_linux);
        } else if ("aix".contains(pOs.toLowerCase())) {
            l.add(Pattern.compile(rut_aix));
            l.add(Pattern.compile(rut_aixA));
            l.add("aix");
            return l;
            // return compiler.compile(rut_aix);
        } else if ("solaris".contains(pOs.toLowerCase())) {
            l.add(Pattern.compile(rut_solaris));
            l.add(Pattern.compile(rut_solarisA));
            l.add("solaris");
            return l;
            // return compiler.compile(rut_solaris);
        } else if ("hp".contains(pOs.toLowerCase())) {
            l.add(Pattern.compile(rut_hp));
            l.add(Pattern.compile(rut_hpA));
            l.add("hp");
            return l;
        } else if ("windows".contains(pOs.toLowerCase())) {
            // return compiler.compile(rut_Tru64);
        }
        return null;
    }

    private String getCommand(String targetIp) {
        String osName = System.getProperty("sun.desktop");
        if (osName.equalsIgnoreCase("Windows")) {
            return cmd_Windows + " " + targetIp;
        } else if (osName.equalsIgnoreCase(OS_Linux)) {
            return cmd_Linux + targetIp;
        } else if (osName.equalsIgnoreCase(OS_AIX)) {
            return cmd_AIX + targetIp;
        } else if (osName.equalsIgnoreCase(OS_Solaris)) {
            return cmd_Solaris + targetIp + " 56 10";
        } else if (osName.equalsIgnoreCase(OS_HP)) {
            return cmd_HP + targetIp + " -n 10";
        } else if (osName.equalsIgnoreCase(OS_Tru64)) {
            return cmd_Tru64 + targetIp;
        }
        return null;
    }

    private String getCommand(String pOs, String targetIp) {
        if ("windows".contains(pOs.toLowerCase())) {
            return cmd_Windows + " " + targetIp;
        } else if ("linux".contains(pOs.toLowerCase())) {
            return cmd_Linux + targetIp;
        } else if ("aix".contains(pOs.toLowerCase())) {
            return cmd_AIX + targetIp;
        } else if ("solaris".contains(pOs.toLowerCase())) {
            return cmd_Solaris + targetIp + " 56 10";
        } else if ("hp".contains(pOs.toLowerCase())) {
            return cmd_HP + targetIp + " -n 10";
        } else if ("tru64".contains(pOs.toLowerCase())) {
            return cmd_Tru64 + targetIp;
        }
        return null;
    }

    @Override
    public String[] getParamMeta() {
        //        return new String[] {  "ping命令接收端" };
        return new String[] { "Destination IP of Ping Command", "Origin_Ip", "Origin_Os" };
    }

    @Override
    public String[] getPropMeta() {
        //        return new String[] { "发送包", "接收包", "丢包率", "最小时间", "最大时间", "平均时间" };
        //        return new String[] { "Sent_Package", "Received_Package", "Lost_Package", "Min_Time", "Max_Time", "Avg_Time" };
        return new String[] { "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8" };
    }

    public List<ResPropertyValue> getPingResult(String ip, String deviceIP) throws CollectorException {
        return testPing(ip, null, deviceIP);
    }
}
